/*
 * main.c
 */

#include <stdlib.h>

#include "../cdef.h"
#include "../sensor.h"

#include "../Application/DEB/DEBC1.h"
#include "../Application/SWTIMER/SWTIMERC1.h"
#include "../Application/UI/LED/LEDC1.h"
#include "../Application/UI/BUTTON/BTNC1.h"
#include "../Application/SENSORS/SNSR/SNSRC1.h"

#include "../Driver/PMM/PMMC1.h"
#include "../Driver/DIO/DIOC1.h"
#include "../Driver/HWTIMER/HWTIMERC1.h"
#include "../Driver/RTC/RTCC1.h"
#include "../Driver/ADC/ADCC1.h"

/* Variable holding system internal flags */
volatile APP_tstSystemFlags APP_stSystemFlags;
volatile APP_tunRequests APP_unRequests;

/* prototypes */
static void APP_vInit( void );
static void APP_vCheckEvents( void );
static void APP_vIdle( void );

int _system_pre_init (void)
{
   /* stop watchdog */
   WDTCTL = WDTPW + WDTHOLD;

   DIO_vReset();

   /* set to max drive strength for xtal startup */
   UCSCTL6 |= XT1DRIVE1_L + XT1DRIVE0_L;

   /* enable LF mode and clear xcap and bypass */
   UCSCTL6 &= ~( XTS + XCAP_3 + XT1BYPASS );
   UCSCTL6 |= XCAP_3;

   UCSCTL3 = SELA__XT1CLK;     // Select XT1 as FLL reference
   UCSCTL4 = SELA__XT1CLK | SELS__DCOCLKDIV | SELM__DCOCLKDIV;

   // Configure CPU clock for 12MHz
   _BIS_SR(SCG0);              // Disable the FLL control loop
   UCSCTL0 = 0x0000;           // Set lowest possible DCOx, MODx
   UCSCTL1 = DCORSEL_5;        // Select suitable range
   UCSCTL2 = FLLD_1 + 365;     // Set DCO Multiplier
   _BIC_SR(SCG0);              // Enable the FLL control loop

   // Worst-case settling time for the DCO when the DCO range bits have been
   // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
   // UG for optimization.
   // 32 x 32 x 12 MHz / 32,768 Hz = 375000 = MCLK cycles for DCO to settle
   __delay_cycles(375000);

   // Loop until XT1 & DCO stabilizes, use do-while to insure that
   // body is executed at least once
   do
   {
      UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + XT1HFOFFG + DCOFFG);
      SFRIFG1 &= ~OFIFG;      // Clear fault flags
   }
   while( ( SFRIFG1 & OFIFG ) );

   /* set drive mode */
   UCSCTL6 &= ~( XT1DRIVE1_L + XT1DRIVE0_L );

   /* turn XT1 on */
   UCSCTL6 &= ~(XT1OFF);

   return 1;
}

static void APP_vInit( void )
{
   PMM_vSetCore( PMMCOREV_1 );

   /* module resets */
   RTC_vReset();
   SWTIM_vReset();
   DEB_vReset();
   LED_vReset();
   BTN_vReset();
   ADC_vReset();
   SNSR_vReset();
   HWTIM_vReset();

   /* flag resets */
   APP_stSystemFlags.unFlags.u8AllFlags = 0;

   /* set the address of the unit */
   APP_stSystemFlags.un32Address.u32DW = 305419896; /* 0x12345678 */

   /* reset offsets - will be populated in get cal data function */
   APP_stSystemFlags.un16TempOffset.u16W = 0;

   /* clear all requests */
   APP_unRequests.u8AllRequests = 0;
}

static inline void APP_vCheckEvents( void )
{
   static const tboFuncPtr pfRunFunctions[] =
   {
         &SWTIM_boUpdateTimer,
         &DEB_boStartDebounce,
         &BTN_boProcessEvent,
         &SNSR_boIncrementMinuteCount,
         &SNSR_boProcessCurrentSensorAction
   };

   uint8 u8i;
   uint8 u8Temp;
   uint8 u8Mask;

   if( APP_unRequests.u8AllRequests != False )
   {
      u8Temp = APP_unRequests.u8AllRequests;

      for( u8i = 0; u8i < 8; u8i++ )
      {
         u8Mask = ( 1 << u8i );
         if( ( u8Temp & u8Mask ) == u8Mask )
         {
            if( pfRunFunctions[u8i]() == True )
            {
               APP_unRequests.u8AllRequests &= ~( u8Mask );
            }
         }
      }
   }
}

static inline void APP_vIdle( void )
{
   /* no more requests to process? go back to sleep */
   if( APP_unRequests.u8AllRequests == 0 )
   {
      _BIS_SR(LPM3_bits);
      __no_operation();
   }
}

void main(void)
{
   APP_vInit();
   __enable_interrupt();

   while(1)
   {
      /* nothing to run - go to sleep */
      APP_vIdle();
      //MSP430_FAST_SET_PIN_TEST2;

      /* woke up - run any pending events */
      APP_vCheckEvents();
      //MSP430_FAST_CLEAR_PIN_TEST2;
   }
}

#pragma vector=AES_VECTOR,                      \
  CC1101_VECTOR,COMP_B_VECTOR,LCD_B_VECTOR,     \
  TIMER1_A0_VECTOR,TIMER0_A1_VECTOR,            \
  USCI_B0_VECTOR,USCI_A0_VECTOR,WDT_VECTOR,     \
  UNMI_VECTOR,SYSNMI_VECTOR,ADC12_VECTOR
__interrupt void ISR_trap(void)
{
   // the following will cause an access violation which results in a PUC reset
   WDTCTL = 0;
}
